package cn.yuli.zookeeper.lock;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
/**
 * 分布式锁
 * @author yuli
 *
 */

import org.apache.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.KeeperException.ConnectionLossException;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.Watcher.Event.EventType;
public class DistributedLock implements Lock {
	private ZooKeeper zk = null;
	private String basePath = "/lock";
	private String node;
	private String preNode;
	private static Logger logger = Logger.getLogger(DistributedLock.class);
	private static int COUNT = 50;
	static int ii = 0;
	private static CountDownLatch cdl = new CountDownLatch(COUNT);
	private CountDownLatch wait = new CountDownLatch(1);
	public static void main(String[] args) {
		for(int i = COUNT;i>=0;i--){
			new Thread(new Runnable() {
				
				public void run() {
					System.out.println("开始创建");
					DistributedLock lock = new DistributedLock();
					cdl.countDown();
//					boolean tryLock = lock.tryLock();
					lock.lock();
					System.out.println("哈哈");
					lock.unlock();
				}
			}).start();;
		}
	}
	public void lock() {
		connectionStart();

		if(!tryLock()){
			try {
				System.out.println(ii++);
				//监听之前的一个节点
				String fullPath = basePath+"/"+preNode;
				System.out.println("监听的节点为--"+preNode);
				zk.exists(fullPath,true);
				wait.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (KeeperException e) {
				e.printStackTrace();
				lock();
			}
		}
		
	}

	public void lockInterruptibly() throws InterruptedException {

	}

	public boolean tryLock() {
		try {
			String string = zk.create(basePath+"/", null, Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
			node = string.substring(string.length()-10, string.length());
			logger.info(node);
			return checkMin();
		} catch (KeeperException e) {
			if(e instanceof ConnectionLossException){
				logger.error("再次尝试加锁");
				tryLock();
			}
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
			return false;
		}
		return false;
	}
	/**
	 * 判断是否是最小的节点
	 * @return
	 */
	public boolean checkMin(){
		try {
			List<String> childrens = zk.getChildren(basePath, false);
//			//如果只有一个节点就是最小的
//			if(childrens.size() < 2){
//				logger.info("只有一个节点");
//				return true;
//			}
			Collections.sort(childrens);//排序
			int i = childrens.indexOf(node);//第一次出现的位置
			synchronized (this.getClass()) {
				
				if(i<0){
					logger.info("本节点丢失");
					return false;
				}else if(i == 0){
					logger.info("本节点是最小的");
					return true;
				}else{
					preNode = childrens.get(i-1);
					return false;
				}
			}
			
			
		} catch (KeeperException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return false;
	}
	public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
		return false;
	}

	public void unlock() {
		connectionStop();
	}

	public Condition newCondition() {
		return null;
	}
	public void connectionStart(){
		try {
			zk = new ZooKeeper("39.108.170.73:2181", 6000, new LockWatcher());
			cdl.await();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	public void connectionStop(){
		try {
			System.out.println("关闭的节点为---"+node);
			zk.close();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	class LockWatcher implements Watcher{

		public void process(WatchedEvent event) {
			if(event.getType() == EventType.NodeDeleted){
				System.out.println("当前的node----"+node+"----删除的node-------"+event.getPath());
				logger.info("前一位节点已经消失："+preNode);
				if(checkMin()){
					logger.info("加锁成功");
					wait.countDown();
				}else{
					lock();
				}
			}
		}
		
	}
}
